﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace GeneticWords
{
    public partial class Form1 : Form
    {
        public class universe_class //Описание вселенной
        {
            public class life_type    //Живой организм
            {

                public Point Pos;            //Позиция нашего животного
                public Point Face;           //Точка лица нашего животного (соседняя клетка). Может выходить за границы игрового поля!
                public String Name;         //Название животного
                public String Actions;      //Строка дейтвий 
                public int Power;           //Количество энергии
                public String Abilities;    //Строка возможностей животного
                public int State;           //Состояние          
                public int Died;
                
                public life_type()
                {
                    Name = "";
                    Actions = "";
                    Power = -1;
                    Abilities = "";
                    State = -1;
                }
            }

            public life_type[] life;
            public int Iteration;
            public universe_class(int MaxLives)
            {                
                life = new life_type[MaxLives];
            }

            public int Get_Alived() //Сичтаем живых
            {
                int col = 0;
                for (int i = 0; i < life.Length; i++)
                {
                    if (life[i].Power > 0) col++;
                }
                return col;
            }

        }

        const int World_Width = 50;
        const int World_Heigh = 50;
        const int World_Z = 1;
        int InitialMaxLives = (int)(World_Width * World_Heigh * 0.01);
        universe_class Universe;// = new world_type[World_Width, World_Heigh, World_Z]; // Мой мир
        Random G_rnd = new Random();
        public Form1()
        {
            InitializeComponent();
            Init_Population();

        }
        
        private void Init_Population()
        {
            Universe = new universe_class(InitialMaxLives); //Создаем новую вселенную
            Random rnd = new Random();
            for (int i = 0; i < Universe.life.Length; i++) //Генерируем жизнь
            {
                
                int X = rnd.Next(0, World_Width);
                int Y = rnd.Next(0, World_Heigh);

                Universe.life[i]=new universe_class.life_type();
                Universe.life[i].Name = "SomeName" + Convert.ToString(X) + "-" + Convert.ToString(Y);
                Universe.life[i].Abilities = "wsad";
                Universe.life[i].Actions = GenActions(Universe.life[i].Abilities);
                Universe.life[i].Pos.X = X;
                Universe.life[i].Pos.Y = Y;
                Universe.life[i].State = 1;
                Universe.life[i].Power = 2;
            }
            Universe.life[0].State = 2;
        }

        private void DrawWorld() //Рисуем Мир
        {
            Graphics Graph = PB.CreateGraphics(); //Рисовать будем тут

            if (Universe.life.Length == 0) { return; }
            int Rect_W = (int)((PB.Width / World_Width));  //Считаем ширину точки 
            int Rect_H = (int)((PB.Height / World_Heigh)); // Считаем высоту точки
            int Rect_result;
            if (Rect_W >= Rect_H)  // Выводим по наименьшему (чтобы на экран влезало)
            {
                Rect_result = Rect_H;
            } else
            {
                Rect_result = Rect_W;
            }

            SolidBrush SBrush = new SolidBrush(Color.White); //Очищаем холст
            Graph.FillRectangle(SBrush, new RectangleF(0, 0, World_Width * Rect_result, World_Heigh * Rect_result));

            //Rect_result = 10;
            for (int i=0; i < Universe.life.Length; i++) //
            {
                if (Universe.life[i].State >= 0) //Если мы нашли жизнь
                {
                    if (Universe.life[i].Power <= 0)
                    {
                        Pen myBrush = new Pen(Color.DarkGreen);
                        Rectangle CurRect = new Rectangle(Universe.life[i].Pos.X * Rect_result, //Позиция X
                                                            Universe.life[i].Pos.Y * Rect_result, // Y
                                                            Rect_result, //Ширина
                                                            Rect_result); //Высота 
                        Graph.DrawRectangle(myBrush, CurRect); //Рисуем ячейку с жизнью
                    }
                    if (Universe.life[i].Power > 0)
                    {                       
                        SolidBrush LBrush = new SolidBrush(Color.Green);
                        if (Universe.life[i].State == 2)
                        {
                            LBrush = new SolidBrush(Color.Blue); //Очищаем холст
                        }                   
                        RectangleF CurRect = new RectangleF(Universe.life[i].Pos.X * Rect_result, //Позиция X
                                                            Universe.life[i].Pos.Y * Rect_result, // Y
                                                            Rect_result, //Ширина
                                                            Rect_result); //Высота 
                        Graph.FillRectangle(LBrush, CurRect);
                        
                    }
                    //MessageBox.Show(Convert.ToString(Universe.life[i].Pos.X) + ":X Y:" + Convert.ToString(Universe.life[i].Pos.Y));
                }   
            }
        }

        private void Iteration() //Обработка действий
        {       
            for (int i = 0; i < Universe.life.Length; i++) //Обрабатываем каждую Жизнь
            {

                if (Universe.life[i].State > 0)
                {
                    if (Universe.life[i].State == 2) //Ручной контроль
                    {
                        Universe.life[i].Actions = textBox1.Text.ToLower();
                    }
                    char[] actions = Universe.life[i].Actions.ToCharArray(); //parsing Actions
                    for (int c = 0; c < actions.Length; c++)
                    {

                        if (!DoAction(i, actions[c])) //Если Действие не было выполнено (любая причина). Пока только столкновение с другой Жизнью.
                        {
                            Universe.life[i].Power--; //Столкновение уменьшает энергию. Больно ведь.
                            if (Universe.life[i].State == 1) //Бот
                            {
                                Universe.life[i].Actions = GenActions(Universe.life[i].Abilities); //Генеруруем новую последовательность действий
                            }
                            if (Universe.life[i].Power <= 0)
                            {
                                Universe.life[i].State = 0;
                                Universe.life[i].Died = Universe.Iteration;
                            }
                            break;  //Прекратить дальнейшую обработку действий
                        }
                    }
                }
                else
                {
                    if (Universe.Iteration - Universe.life[i].Died >= 50)
                    {
                        Universe.life[i].State = -1;
                    }
                }
                //MessageBox.Show(Universe.life[i].Actions);
            }
            Universe.Iteration++; //Подсчитываем итерации
        }

        private string GenActions(string Abilities) //Генерируем список дейтсвий исходя из строки возможностей
        {
            
            string Actions = "";
            char[] Ability = Abilities.ToCharArray(); //parsing Actions
            for (int i = 0; i < 2; i++)
            {
                Actions += Ability[G_rnd.Next(Abilities.Length)];
               
            }
            return Actions;
        }

        private bool IsClear(int X, int Y) //Проверка столкновений
        {
            for (int i = 0; i < Universe.life.Length; i++)
            {
                if (Universe.life[i].Pos.X == X && Universe.life[i].Pos.Y == Y)
                {
                    if (Universe.life[i].State < 0 ) //Исчезнувыших не считаем (-1)
                    {
                        return true;
                    }
                    return false;
                }
            }
            return true;
        }

        private Point MapProcessor(Point pt) //Обрабатывает позицию для всех оперций - СКЛЕЙКА КАРТЫ (мир то круглый)
        {
            //Point Npt;
            if (pt.Y > World_Heigh-1)
            {
                pt.Y=0;
            }
            if (pt.Y < 0)
            {
                pt.Y = World_Heigh-1;
            }
            if (pt.X > World_Width-1)
            {
                pt.X = 0;
            }
            if (pt.X < 0)
            {
                pt.X = World_Width-1;
            }            
            return pt;
        }

        private bool DoAction(int Life_pos, char Action)
        {
            Point NewPos=Universe.life[Life_pos].Pos;
            //Point FacePos=Universe.life[Life_pos].Pos;
            bool Action_success = false;
           switch (Action)
            {
                case 'w':
                   NewPos.Y--;                                      
                   NewPos = MapProcessor(NewPos);
                   
                  /* Universe.life[Life_pos].Face.X = X_new;    //Располагаем лицо животного в сторону движения (+1 клетка в сторону движения). Может выходить за границы поля.
                   Universe.life[Life_pos].Face.Y = Y_new -1;*/
                   if (IsClear(NewPos.X, NewPos.Y))
                   {
                       Universe.life[Life_pos].Pos=NewPos;  //Перемещаемся в нужную сторону
                       Action_success = true;
                   }
                   break;
                case 's':
                   NewPos.Y++;                                      
                   NewPos = MapProcessor(NewPos);
                   
                  /* Universe.life[Life_pos].Face.X = X_new;    //Располагаем лицо животного в сторону движения (+1 клетка в сторону движения). Может выходить за границы поля.
                   Universe.life[Life_pos].Face.Y = Y_new -1;*/
                   if (IsClear(NewPos.X, NewPos.Y))
                   {
                       Universe.life[Life_pos].Pos=NewPos;  //Перемещаемся в нужную сторону
                       Action_success = true;
                   }
                    break;
                case 'a':
                   NewPos.X--;                                      
                   NewPos = MapProcessor(NewPos);
                   
                  /* Universe.life[Life_pos].Face.X = X_new;    //Располагаем лицо животного в сторону движения (+1 клетка в сторону движения). Может выходить за границы поля.
                   Universe.life[Life_pos].Face.Y = Y_new -1;*/
                   if (IsClear(NewPos.X, NewPos.Y))
                   {
                       Universe.life[Life_pos].Pos=NewPos;  //Перемещаемся в нужную сторону
                       Action_success = true;
                   }
                    break;
                case 'd':
                   NewPos.X++;                                      
                   NewPos = MapProcessor(NewPos);
                   
                  /* Universe.life[Life_pos].Face.X = X_new;    //Располагаем лицо животного в сторону движения (+1 клетка в сторону движения). Может выходить за границы поля.
                   Universe.life[Life_pos].Face.Y = Y_new -1;*/
                   if (IsClear(NewPos.X, NewPos.Y))
                   {
                       Universe.life[Life_pos].Pos=NewPos;  //Перемещаемся в нужную сторону
                       Action_success = true;
                   }
                    break;
           }
            return Action_success;
        }

        private void Iteration_btn_Click(object sender, EventArgs e)
        {
            Iteration();
            label1.Text = Universe.Iteration.ToString() + " Alived:" + Universe.Get_Alived().ToString();
            textBox1.Focus();
            DrawWorld();
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            DrawWorld();
        }

        private void Init_pop_Click(object sender, EventArgs e)
        {
            Init_Population();
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            DrawWorld();
        }

        private void textBox1_KeyUp(object sender, KeyEventArgs e)
        {
            textBox1.Text += e.KeyCode.ToString();
            char[] cs = textBox1.Text.ToCharArray();
            if (cs.Length > 2)
            {
                textBox1.Text = cs[cs.Length-2].ToString();
                textBox1.Text += cs[cs.Length-1].ToString();
            }
        }

        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            label2.Text = e.KeyCode.ToString();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (Iteration_checkbox.Checked)
            {
                Iteration_btn_Click(sender, e);
            }
        }

    }
}
